# -*- coding: utf-8 -*-
from __future__ import absolute_import

from PyQt4.QtGui import QTabWidget
from PyQt4.QtGui import QIcon
from PyQt4.QtGui import QHBoxLayout
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QMessageBox
from PyQt4.QtGui import QColor
from PyQt4.QtGui import QMenu
from PyQt4.QtGui import QPushButton
from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QClipboard
from PyQt4.QtCore import Qt
from PyQt4.QtCore import SIGNAL

from ninja_ide import resources
from ninja_ide.core import settings
from ninja_ide.core import file_manager
from ninja_ide.gui.editor import editor
from ninja_ide.tools import styles
from ninja_ide.gui.main_panel import browser_widget


class TabWidget(QTabWidget):

###############################################################################
# TabWidget SIGNALS
###############################################################################
    """
    tabCloseRequested(int)
    dropTab(QTabWidget)
    scrollEditor(QWheelEvent, QTabWidget)
    saveActualEditor()
    allTabsClosed()
    changeActualTab(QTabWidget)
    splitTab(QTabWidget, int, bool)
    reopenTab(QTabWidget, QString)
    runFile()
    addToProject(QString)
    syntaxChanged(QWidget, QString)
    reloadFile()
    navigateCode(bool, int)
    """
###############################################################################

    def __init__(self):
        QTabWidget.__init__(self)
        self.setTabsClosable(True)
        self.setMovable(True)
        self.setAcceptDrops(True)
        self.notOpening = True
        self.__lastOpened = []
        self._resyntax = []
        self.navigator = TabNavigator()
        self.setCornerWidget(self.navigator, Qt.TopRightCorner)
        #On some plataforms there are problem with focusInEvent
        self.question_already_open = False
        #Keep track of the tab titles
        self.titles = []

        self.connect(self, SIGNAL("tabCloseRequested(int)"), self.removeTab)
        self.connect(self.navigator.btnPrevious, SIGNAL("clicked()"),
            lambda: self._navigate_code(False))
        self.connect(self.navigator.btnNext, SIGNAL("clicked()"),
            lambda: self._navigate_code(True))

    def _navigate_code(self, val):
        op = self.navigator.operation
        self.emit(SIGNAL("navigateCode(bool, int)"), val, op)

    def _add_to_last_opened(self, path):
        self.__lastOpened.append(path)
        if len(self.__lastOpened) > settings.MAX_REMEMBER_TABS:
            self.__lastOpened = self.__lastOpened[1:]

    def add_tab(self, widget, title, index=None):
        try:
            if index:
                inserted_index = self.insertTab(index, widget, title)
            else:
                inserted_index = self.addTab(widget, title)
            self.setCurrentIndex(inserted_index)
            self.expand_tab_name(title)
            widget.setFocus()
            return inserted_index
        except AttributeError, reason:
            print reason
            print("Widget couldn't be added, doesn't inherit from ITabWidget")

    def expand_tab_name(self, title):
        if title == 'New Document':
            return
        elif title not in self.titles:
            self.titles.append(title)
            return
        indexes = [i for i in xrange(self.count())
            if type(self.widget(i)) is editor.Editor and \
            self.tabText(i) == title and \
            self.widget(i).ID]
        for i in indexes:
            newName = file_manager.create_path(
                file_manager.get_basename(
                    file_manager.get_folder(self.widget(i).ID)),
                title)
            while newName in self.titles:
                path = self.widget(i).ID
                tempDir = path[:path.rfind(newName)]
                newName = file_manager.create_path(
                    file_manager.get_basename(
                        file_manager.get_folder(tempDir)),
                    '..',
                    title)
            self.titles.append(newName)
            self.setTabText(i, newName)

    def tab_was_modified(self, val):
        ed = self.currentWidget()
        if type(ed) is editor.Editor and self.notOpening and val:
            ed.textModified = True
            self.tabBar().setTabTextColor(self.currentIndex(), QColor(Qt.red))

    def focusInEvent(self, event):
        QTabWidget.focusInEvent(self, event)
        self.emit(SIGNAL("changeActualTab(QTabWidget)"), self)

        #custom behavior after the default
        editorWidget = self.currentWidget()
        if not editorWidget:
            return
        #Check never saved
        if editorWidget.newDocument:
            return
        #Check if we should ask to the user
        if not editorWidget.ask_if_externally_modified:
            return
        #Check external modifications!
        if editorWidget.check_external_modification() and \
            not self.question_already_open:
                #dont ask again if you are already asking!
            self.question_already_open = True
            val = QMessageBox.question(self, 'The file has changed on disc!',
                                self.tr("Do you want to reload it?"),
                                QMessageBox.Yes, QMessageBox.No)
            if val == QMessageBox.Yes:
                self.emit(SIGNAL("reloadFile()"))
            else:
                #dont ask again while the current file is open
                editorWidget.ask_if_externally_modified = False
        #we can ask again
        self.question_already_open = False

    def tab_was_saved(self, ed):
        index = self.indexOf(ed)
        self.tabBar().setTabTextColor(index, QColor(Qt.gray))

    def is_open(self, identifier):
        """Check if a Tab with id = identifier is open"""
        for i in xrange(self.count()):
            if self.widget(i) == identifier:
                return True
        return False

    def move_to_open(self, identifier):
        """Set the selected Tab for the widget with id = identifier"""
        for i in xrange(self.count()):
            if self.widget(i) == identifier:
                self.setCurrentIndex(i)
                return

    def removeTab(self, index):
        """Remove the Tab at the selected index and check if the
        widget was modified and need to execute any saving"""
        if index != -1:
            self.setCurrentIndex(index)
            editorWidget = self.currentWidget()
            if type(editorWidget) is editor.Editor:
                val = QMessageBox.No
                if editorWidget.textModified:
                    fileName = self.tabBar().tabText(self.currentIndex())
                    val = QMessageBox.question(
                        self, self.tr('The file %1 was not saved').arg(
                            fileName),
                            self.tr("Do you want to save before closing?"),
                            QMessageBox.Yes | QMessageBox.No | \
                            QMessageBox.Cancel)
                if val == QMessageBox.Cancel:
                    return
                elif val == QMessageBox.Yes:
                    self.emit(SIGNAL("saveActualEditor()"))
                    if editorWidget.textModified:
                        return
            if type(editorWidget) == browser_widget.BrowserWidget:
                editorWidget.shutdown_pydoc()
            elif type(editorWidget) is editor.Editor and editorWidget.ID:
                self._add_to_last_opened(editorWidget.ID)
            if unicode(self.tabText(index)) in self.titles:
                self.titles.remove(unicode(self.tabText(index)))
            super(TabWidget, self).removeTab(index)
            if self.currentWidget() is not None:
                self.currentWidget().setFocus()
            else:
                self.emit(SIGNAL("allTabsClosed()"))

    def setTabText(self, index, text):
        QTabWidget.setTabText(self, index, text)
        if text not in self.titles:
            self.expand_tab_name(text)

    def close_tab(self):
        self.removeTab(self.currentIndex())

    def get_documents_data(self):
        """Return Editors: path, project, cursor position"""
        files = []
        for i in range(self.count()):
            if (type(self.widget(i)) is editor.Editor) \
            and self.widget(i).ID != '':
                files.append([self.widget(i).ID,
                    self.widget(i).get_parent_project(),
                    self.widget(i).get_cursor_position()])
                self.widget(i)._sidebarWidget._save_breakpoints_bookmarks()
        return files

#    def mouseMoveEvent(self, event):
#        if event.buttons() != Qt.RightButton:
#            return
#        mimeData = QMimeData()
#        drag = QDrag(self)
#        drag.setMimeData(mimeData)
#        drag.setHotSpot(event.pos() - self.rect().topLeft())
#        dropAction = drag.start(Qt.MoveAction)
#        if dropAction == Qt.MoveAction:
#            self.close()

    def mousePressEvent(self, event):
        QTabWidget.mousePressEvent(self, event)
        if event.button() == Qt.RightButton:
            index = self.tabBar().tabAt(event.pos())
            self.setCurrentIndex(index)
            widget = self.widget(index)
            if type(widget) is editor.Editor:
                #show menu
                menu = QMenu()
                actionAdd = menu.addAction(self.tr("Add to Project..."))
                actionRun = menu.addAction(self.tr("Run this File!"))
                menuSyntax = menu.addMenu(self.tr("Change Syntax"))
                self._create_menu_syntax(menuSyntax)
                menu.addSeparator()
                actionClose = menu.addAction(self.tr("Close This Tab"))
                actionCloseAll = menu.addAction(self.tr("Close All Tabs"))
                actionCloseAllNotThis = menu.addAction(
                    self.tr("Close Other Tabs"))
                actionSplitH = menu.addAction(
                    self.tr("Split this Tab (Horizontally)"))
                actionSplitV = menu.addAction(
                    self.tr("Split this Tab (Vertically)"))
                menu.addSeparator()
                actionCopyPath = menu.addAction(
                    self.tr("Copy file location to Clipboard"))
                actionReopen = menu.addAction(
                    self.tr("Reopen last closed File"))
                if len(self.__lastOpened) == 0:
                    actionReopen.setEnabled(False)
                #Connect actions
                self.connect(actionRun, SIGNAL("triggered()"),
                    self._run_this_file)
                self.connect(actionAdd, SIGNAL("triggered()"),
                    self._add_to_project)
                self.connect(actionSplitH, SIGNAL("triggered()"),
                    lambda: self._split_this_tab(True))
                self.connect(actionSplitV, SIGNAL("triggered()"),
                    lambda: self._split_this_tab(False))
                self.connect(actionClose, SIGNAL("triggered()"),
                    lambda: self.removeTab(index))
                self.connect(actionCloseAllNotThis, SIGNAL("triggered()"),
                    self._close_all_tabs_except_this)
                self.connect(actionCloseAll, SIGNAL("triggered()"),
                    self._close_all_tabs)
                self.connect(actionCopyPath, SIGNAL("triggered()"),
                    self._copy_file_location)
                self.connect(actionReopen, SIGNAL("triggered()"),
                    self._reopen_last_tab)
                menu.exec_(event.globalPos())
        if event.button() == Qt.MidButton:
            index = self.tabBar().tabAt(event.pos())
            self.removeTab(index)

    def _create_menu_syntax(self, menuSyntax):
        syntax = settings.SYNTAX.keys()
        syntax.sort()
        for syn in syntax:
            menuSyntax.addAction(syn)
            self.connect(menuSyntax, SIGNAL("triggered(QAction*)"),
                self._reapply_syntax)

    def _reapply_syntax(self, syntaxAction):
        if [self.currentIndex(), syntaxAction] != self._resyntax:
            self._resyntax = [self.currentIndex(), syntaxAction]
            self.emit(SIGNAL("syntaxChanged(QWidget, QString)"),
                self.currentWidget(), syntaxAction.text())

    def _run_this_file(self):
        self.emit(SIGNAL("runFile()"))

    def _add_to_project(self):
        self.emit(SIGNAL("changeActualTab(QTabWidget)"), self)
        widget = self.currentWidget()
        if type(widget) is editor.Editor:
            self.emit(SIGNAL("addToProject(QString)"), widget.ID)

    def _reopen_last_tab(self):
        self.emit(SIGNAL("reopenTab(QTabWidget, QString)"),
        self, self.__lastOpened.pop())

    def _split_this_tab(self, orientation):
        self.emit(SIGNAL("splitTab(QTabWidget, int, bool)"),
            self, self.currentIndex(), orientation)

    def _copy_file_location(self):
        widget = self.currentWidget()
        QApplication.clipboard().setText(widget.ID, QClipboard.Clipboard)

    def _close_all_tabs(self):
        for i in xrange(self.count()):
            self.removeTab(0)

    def _close_all_tabs_except_this(self):
        self.tabBar().moveTab(self.currentIndex(), 0)
        for i in xrange(self.count()):
            if self.count() > 1:
                self.removeTab(1)

#    def dragEnterEvent(self, event):
#        event.accept()
#
#    def dropEvent(self, event):
#        event.accept()
#        self.emit(SIGNAL("dropTab(QTabWidget)"), self)

    def wheelScroll(self, event):
        self.emit(SIGNAL("scrollEditor(QWheelEvent, QTabWidget)"), event, self)

    def _check_unsaved_tabs(self):
        val = False
        for i in range(self.count()):
            if type(self.widget(i)) is editor.Editor:
                val = val or self.widget(i).textModified
        return val

    def change_tab(self):
        if self.currentIndex() < (self.count() - 1):
            self.setCurrentIndex(self.currentIndex() + 1)
        else:
            self.setCurrentIndex(0)

    def change_tab_reverse(self):
        if self.currentIndex() > 0:
            self.setCurrentIndex(self.currentIndex() - 1)
        else:
            self.setCurrentIndex(self.count() - 1)


class TabNavigator(QWidget):

    def __init__(self):
        QWidget.__init__(self)
        self.setContextMenuPolicy(Qt.DefaultContextMenu)
        self.setMinimumHeight(38)
        hbox = QHBoxLayout(self)
        self.btnPrevious = QPushButton(
            QIcon(resources.IMAGES['nav-code-left']), '')
        self.btnPrevious.setToolTip(
            self.tr("Right click to change navigation options"))
        styles.set_style(self.btnPrevious, 'tab-navigator')
        self.btnNext = QPushButton(
            QIcon(resources.IMAGES['nav-code-right']), '')
        self.btnNext.setToolTip(
            self.tr("Right click to change navigation options"))
        styles.set_style(self.btnNext, 'tab-navigator')
        hbox.addWidget(self.btnPrevious)
        hbox.addWidget(self.btnNext)
        self.setContentsMargins(0, 0, 0, 0)

        self.menuNavigate = QMenu(self.tr("Navigate"))
        self.codeAction = self.menuNavigate.addAction(
            self.tr("Code Jumps"))
        self.codeAction.setCheckable(True)
        self.codeAction.setChecked(True)
        self.bookmarksAction = self.menuNavigate.addAction(
            self.tr("Bookmarks"))
        self.bookmarksAction.setCheckable(True)
        self.breakpointsAction = self.menuNavigate.addAction(
            self.tr("Breakpoints"))
        self.breakpointsAction.setCheckable(True)

        # 0 = Code Jumps
        # 1 = Bookmarks
        # 2 = Breakpoints
        self.operation = 0

        self.connect(self.codeAction, SIGNAL("triggered()"),
            self._show_code_nav)
        self.connect(self.breakpointsAction, SIGNAL("triggered()"),
            self._show_breakpoints)
        self.connect(self.bookmarksAction, SIGNAL("triggered()"),
            self._show_bookmarks)

    def contextMenuEvent(self, event):
        self.menuNavigate.exec_(event.globalPos())

    def _show_bookmarks(self):
        self.btnPrevious.setIcon(QIcon(resources.IMAGES['book-left']))
        self.btnNext.setIcon(QIcon(resources.IMAGES['book-right']))
        self.bookmarksAction.setChecked(True)
        self.breakpointsAction.setChecked(False)
        self.codeAction.setChecked(False)
        self.operation = 1

    def _show_breakpoints(self):
        self.btnPrevious.setIcon(QIcon(resources.IMAGES['break-left']))
        self.btnNext.setIcon(QIcon(resources.IMAGES['break-right']))
        self.bookmarksAction.setChecked(False)
        self.breakpointsAction.setChecked(True)
        self.codeAction.setChecked(False)
        self.operation = 2

    def _show_code_nav(self):
        self.btnPrevious.setIcon(QIcon(resources.IMAGES['nav-code-left']))
        self.btnNext.setIcon(QIcon(resources.IMAGES['nav-code-right']))
        self.bookmarksAction.setChecked(False)
        self.breakpointsAction.setChecked(False)
        self.codeAction.setChecked(True)
        self.operation = 0
